#include <cxxomfort/base.hpp>
#include <cxxomfort/algorithm.hpp>
#include <cxxomfort/functional.hpp>
#include <cxxomfort/iterator.hpp>
#include <cxxomfort/typeindex.hpp>
#include <cxxomfort/random.hpp>
#include <cxxomfort/library/foreach.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <cstdio>

const unsigned LIM=100;

struct modu {
	unsigned operator() (unsigned u) const { return '/' + u % ('~'-'/' + 1); }
	template <typename Gen>
	unsigned operator() (Gen& g) const { return this->operator()(g()); }
	// needed for C++03 tr1/bind
	template <typename Sig> struct result { typedef unsigned type; };
};

bool pred_z (unsigned char u) {
	return ispunct(u);
}

bool sorter (unsigned char n1, unsigned char n2) {
	bool uc2 [2] = { (bool)ispunct(n1), (bool)ispunct(n2) };
	if (uc2[0]==uc2[1]) {
		return n1 < n2;
	} else {
		return uc2[0];
	}
}

typedef std::ranlux24_base Gen_t;
typedef std::vector<unsigned char> VecType;


int main () {
	using namespace std;
	VecType Ve (LIM);
	modu mo;
	Gen_t Ge(time(0));
	cout<< "Generating "<< LIM<< " values"<< endl;
	generate(begin(Ve), end(Ve), bind(mo,Ge));
	cout<< "All values: "<< endl;
	CXXO_FOREACH(unsigned char u, Ve) { cout<< u<< " "; }
	cout<< "\n---"<< endl;

	cout<< "Filtering values in the original list with copy_if:"<< endl;
	cout<< "* numbers only: ";
	copy_if(begin(Ve), end(Ve), ostream_iterator<unsigned char>(cout, " "), ::isdigit );
	cout<< endl;
	cout<< "* lowercase only: ";
	copy_if(begin(Ve), end(Ve), ostream_iterator<unsigned char>(cout), ::islower );
	cout<< "\n";
	cout<< "\n----\n";

#if (CXXOMFORT_IMPLEMENTS_algorithm_sorted)
	cout<< "Testing sorting algorithms via fn:sorter:\n";
	VecType VeSorted(Ve);
	cout<< "sort, is_sorted"<< endl;
	cout<< is_sorted(begin(VeSorted), end(VeSorted), sorter)<< endl;
	cout<< "Sorting via sorter..."<< endl;
	sort(begin(VeSorted), end(VeSorted), sorter);
	cout<< "Testing sorting algorithms via fn:sorter: ";
	cout<< is_sorted(begin(VeSorted), end(VeSorted), sorter)<< endl;
	CXXO_FOREACH(unsigned char u, VeSorted) { cout<< u<< " "; }
#else
	cout<< "C++11 sorting algorithms not implemented"<< endl;
#endif
	cout<< "\n----\n";

#if (CXXOMFORT_IMPLEMENTS_algorithm_allanynoneof)
	cout<< "Testing amount_of algorithms from C++11:\n";
	cout<< "[any|all|none]_of, partition_copy"<< endl;
	vector<VecType> splits(2);
	// split the list in two
	cout<< "Partitioning the original list in two:\n";
	partition_copy(begin(Ve), end(Ve)
	, back_inserter(splits[true]), back_inserter(splits[false])
	, pred_z);

	cout<< " Predicate match no:  "<< endl;
	CXXO_FOREACH(unsigned char u, splits[false]) {
		cout<< u<< " ";
	}
	cout<< "\n---"<< endl;
	cout<< " Predicate match yes:  "<< endl;
	CXXO_FOREACH(unsigned char u, splits[true]) {
		cout<< u<< " ";
	}
	cout<< "\n---"<< endl;
	cout<< " Verifying predicate match yes:  "<< endl;
	cout<< "any_of   : "<< any_of(begin(splits[true]), end(splits[true]), pred_z)<< endl;
	cout<< "all_of   : "<< all_of(begin(splits[true]), end(splits[true]), pred_z)<< endl;
	cout<< "none_of  : "<< none_of(begin(splits[true]), end(splits[true]), pred_z)<< endl;
	cout<< endl;

#else
	cout<< "C++11 amount_of predicates not implemented"<< endl;
#endif

}
